package com.iyue.util.file;

import java.io.DataOutputStream;
import java.io.File;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.io.UnsupportedEncodingException;
import java.net.HttpURLConnection;
import java.net.URL;
import java.net.URLEncoder;
import java.util.HashMap;
import java.util.Iterator;
import java.util.List;
import java.util.Map;

import javax.servlet.http.HttpServletRequest;

import org.apache.commons.fileupload.FileItem;
import org.apache.commons.fileupload.FileItemFactory;
import org.apache.commons.fileupload.disk.DiskFileItemFactory;
import org.apache.commons.fileupload.servlet.ServletFileUpload;

import com.iyue.framework.secu.base64.Base64;

public class PicaFileUploader {

	/**
	 * 附件为空
	 */
	public final static String FILE_NULL = "0";
	/**
	 * 文件大小超出范围
	 */
	public final static String FILE_SIZE_OVER = "1";
	/**
	 * 上传文件类型错误
	 */
	public final static String FILE_TYPE_ERROR = "2";
	/**
	 * 文件上传失败
	 */
	public final static String FILE_UPLOAD_FAILURE = "-1";
	/**
	 * 图片
	 */
	public final static String FILE_TYPE_IMAGE = "p";
	/**
	 * 声音
	 */
	public final static String FILE_TYPE_SOUND = "s";
	/**
	 * 视频
	 */
	public final static String FILE_TYPE_VIDEO = "v";
	/**
	 * 任意
	 */
	public final static String FILE_TYPE_ANY = "a";

	/**
	 * 文件存放路径
	 */
	public String filepath;
	/**
	 * 上传服务地址
	 */
	private String baseUrl;
	/**
	 * 默认允许上传文件大小
	 */
	public long defaultSize;
	/**
	 * 允许上传的图片格式
	 */
	public String[] picture;
	/**
	 * 允许上传的声音格式
	 */
	public String[] sound;
	/**
	 * 允许上传的视频格式
	 */
	public String[] video;

	public String getFilepath() {
		return filepath;
	}

	public void setFilepath(String filepath) {
		this.filepath = filepath;
	}

	public String getBaseUrl() {
		return baseUrl;
	}

	public void setBaseUrl(String baseUrl) {
		this.baseUrl = baseUrl;
	}

	public long getDefaultSize() {
		return defaultSize;
	}

	public void setDefaultSize(long defaultSize) {
		this.defaultSize = defaultSize;
	}

	public String[] getPicture() {
		return picture;
	}

	public void setPicture(String[] picture) {
		this.picture = picture;
	}

	public String[] getSound() {
		return sound;
	}

	public void setSound(String[] sound) {
		this.sound = sound;
	}

	public String[] getVideo() {
		return video;
	}

	public void setVideo(String[] video) {
		this.video = video;
	}

	/**
	 * 上传
	 * 
	 * @param request
	 * @param type
	 * @param username
	 * @return
	 */
	@SuppressWarnings("unchecked")
	public Map<String, String> upload(HttpServletRequest request, String type,
			String username) {
		FileItemFactory factory = new DiskFileItemFactory();
		ServletFileUpload up = new ServletFileUpload(factory);
		up.setHeaderEncoding("UTF-8");

		List<FileItem> items = null;
		try {
			items = up.parseRequest(request);
		} catch (Exception e) {
			e.printStackTrace();
			return null;
		}

		if (items == null) {
			return null;
		}

		Iterator<FileItem> iter = items.iterator();
		Map<String, String> ret = new HashMap<String, String>();

		while (iter.hasNext()) {
			FileItem item = iter.next();
			if (item.isFormField()) {
				try {
					ret.put(item.getFieldName(), item.getString("UTF-8"));
				} catch (UnsupportedEncodingException e) {
					e.printStackTrace();
				}
			} else {
				String result = process(item, type, username);
				ret.put(item.getFieldName(), result);
			}
		}

		return ret;
	}

	/**
	 * 上传文件
	 * 
	 * @param item
	 * @param type
	 * @param username
	 * @return
	 */
	private String process(FileItem item, String type, String username) {

		long size = item.getSize();
		if (size > defaultSize) {
			return FILE_SIZE_OVER;
		}

		if (size == 0) {
			return FILE_NULL;
		}

		String fileType = item.getContentType();
		if (!tell(fileType, type)) {
			return FILE_TYPE_ERROR;
		}

		// 如果有服务器地址，则说明上传到远程服务器
		if (baseUrl != null && baseUrl.length() > 0) {
			return uploadByUrl(item, username);
		}

		// 如果没有配置本地路径，则上传失败
		if (filepath == null || filepath.length() <= 0) {
			return null;
		}

		String fileName = item.getName();
		boolean isInMemory = item.isInMemory();

		File dir = new File(filepath);
		if (!dir.exists()) {
			dir.mkdir();
		}

		String file = "";
		try {
			if (isInMemory) {
				File upfile = new File(filepath, fileName);
				item.write(upfile);
				file = filepath + upfile.getName();
			} else {
				InputStream in = item.getInputStream();
				file = filepath + filename(username);
				OutputStream os = new FileOutputStream(file);

				int bytesRead = 0;
				int ls = Integer.parseInt(Long.toString(size));
				byte[] buffer = new byte[ls];
				while ((bytesRead = in.read(buffer, 0, ls)) != -1) {
					os.write(buffer, 0, bytesRead);
				}
				os.close();
				in.close();
			}
		} catch (Exception e) {
			e.printStackTrace();
			return FILE_UPLOAD_FAILURE;
		}

		return file;
	}

	private boolean tell(String fileType, String type) {
		fileType = fileType.toLowerCase();

		if (FILE_TYPE_ANY.equals(type)) {
			return true;
		}

		if (FILE_TYPE_IMAGE.equals(type)) {
			return image(fileType);
		}

		if (FILE_TYPE_SOUND.equals(type)) {
			return sound(fileType);
		}

		if (FILE_TYPE_VIDEO.equals(type)) {
			return video(fileType);
		}

		return false;
	}

	private boolean video(String fileType) {
		int length = video.length;
		for (int i = 0; i < length; i++) {
			if (fileType.indexOf(video[i]) >= 0) {
				return true;
			}
		}

		return false;
	}

	private boolean sound(String fileType) {
		int length = sound.length;
		for (int i = 0; i < length; i++) {
			if (fileType.indexOf(sound[i]) >= 0) {
				return true;
			}
		}

		return false;
	}

	private boolean image(String fileType) {
		int length = picture.length;
		for (int i = 0; i < length; i++) {
			if (fileType.indexOf(picture[i]) >= 0) {
				return true;
			}
		}

		return false;
	}

	private String filename(String username) {
		String filename = username + System.currentTimeMillis();

		//Base64 aa = new Base64();
		byte[] buf = Base64.encode(filename.getBytes());

		return new String(buf);
	}

	private String uploadByUrl(FileItem item, String username) {
		String ret = "-1";
		HttpURLConnection http;
		try {
			String u = URLEncoder.encode(item.getName(), "UTF-8");
			URL urls = new URL(baseUrl + "/" + u);
			http = (HttpURLConnection) urls.openConnection();
			http.setDoOutput(true);
			http.setDoInput(true);
			http.setRequestMethod("POST");
			http.setRequestProperty("Upload-Auth", username + ";" + username);
			http.setRequestProperty("Upload-Service", "sns");
			DataOutputStream out = new DataOutputStream(http.getOutputStream());
			InputStream in = item.getInputStream();
			byte[] buf = new byte[1024];
			int pos = 0;
			while ((pos = in.read(buf, 0, 1024)) > 0) {
				out.write(buf, 0, pos);
			}
			out.flush();
			out.close();

			return in(http.getInputStream());
		} catch (Exception ex) {
			ex.printStackTrace();
		}

		return ret;
	}

	private String in(InputStream in) throws IOException,
			UnsupportedEncodingException {
		StringBuffer sb = new StringBuffer();
		byte[] buf = new byte[1024];
		int pos;
		while ((pos = in.read(buf, 0, 1024)) > 0) {
			sb.append(new String(buf, 0, pos, "UTF-8"));
		}
		in.close();

		return sb.toString();
	}
}
